/************************************
 文件明 ：  bsp_uart.c
 作者   ：  胡秋峰
 描述   ：  UART驱动头文件
 ************************************/
#include "bsp_uart.h"

/**
 * @描述    ： 初始化串口1，波特率115200
 * @参数    ： 无
 * @返回值  ： 无 
 */
void uart1_init(void)
{
    /* 1、初始化串口IO */
    uart1_io_init();

    /* 2、初始化UART1 */
    uart_disable(UART1);
    uart_soft_reset(UART1);

    UART1->UCR1 = 0;
    UART1->UCR1 &= ~(0x1 << 14);
    /* 
     * 设置UART UCR2寄存器，设置字长，停止位，校验模式，关闭硬件流控
     * [14]:    1   忽略rts引脚
     * [8]:     0   关闭奇偶校验位
     * [6]:     0   1位停止位
     * [5]:     1   8位数据位   
     * [2]:     1   打开发送
     * [1]:     1   打开接收
     */ 
    UART1->UCR2 = 0;
    UART1->UCR2 |= (0x1 << 14) | (0x1 << 5) | (0x1 << 2) | (0x1 << 1);
    UART1->UCR3 |= (0x1 << 2);  /* bit2必须为1 */

    /*
     * 设置波特率
     * 波特率Baund Rate = Ref Freq / (16*(UBMR+1)/(UBIR+1))
     * 如果要设置波特率为115200可以使用如下参数
     * Ref Freq = 80MHZ UFCR[9:7] = 101，表示1分频
     * UBMR = 3124
     * UBIR = 71
     */
    UART1->UFCR &= ~(0x7 << 7);
    UART1->UFCR |= (0x5 << 7);
    UART1->UBIR = 71;
    UART1->UBMR = 3124;

#if 0
    uart_set_baudrate(UART1, 115200, 80000000);
#endif
    
    uart_ensable(UART1);
}

/**
 * @描述    ： 初始化串口1所使用的引脚
 * @参数    ： 无
 * @返回值  ： 无 
 */
void uart1_io_init(void)
{
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0);
}

/**
 * @描述                ： 波特率计算
 * @参数 - base         ： 要计算的串口
 * @参数 - baud_rate    ： 要使用的波特率
 * @参数 - src_clock_hz ： 串口时钟源频率
 * @返回值              ： 无 
 */
void uart_set_baud_rate(UART_Type *base, uint32_t baud_rate, uint32_t src_clock_hz)
{
    // uint32_t numerator = 0U;
    // uint32_t denominator = 0U;
    // uint32_t divisor = 0U;
    // uint32_t ref_freq_div = 0U;
    // uint32_t divider = 1U;
    // uint32_t baud_diff = 0U;
    // uint32_t temp_numerator = 0U;
    // uint32_t temp_denominator = 0U;

    // /* get the approximately maximun divsor */
    // numerator = src_clock_hz;
    // denominator = baud_rate << 4;
    // divisor = 1;

    // while (denominator != 0)
    // {
    //     divisor = denominator;
    //     denominator = numerator % denominator;
    //     numerator = divisor;
    // }
    // numerator = src_clock_hz / divisor;
    // denominator = (baud_rate << 4) / divisor;
    
    // /* numerator ranges from 1~7 * 64k */
    // /* denominator ranges from 1~64k */
    // if ((numerator > (UART_UBIR_INC_MASK*7))
    //  || (denominator > UART_UBIR_INC_MASK))
    // {
    //     uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK*7) + 1;
    //     uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;
    //     uint32_t max = m > n ? m : n;
    //     numerator /= max;
    //     denominator /= max;
    //     if (0 == numerator)
    //     {
    //         numerator = 1;
    //     }
    //     if (0 == denominator)
    //     {
    //         denominator = 1;
    //     }
    // }
    // divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;
    
    // switch (divider)
    // {
    // case 1:
    //     ref_freq_div = 0x05;
    //     break;
    // case 2:
    //     ref_freq_div = 0x04;
    //     break;
    // case 3:
    //     ref_freq_div = 0x03;
    //     break;
    // case 4:
    //     ref_freq_div = 0x02;
    //     break;
    // case 5:
    //     ref_freq_div = 0x01;
    //     break;
    // case 6:
    //     ref_freq_div = 0x00;
    //     break;
    // case 7:
    //     ref_freq_div = 0x06;
    //     break;
    // default:
    //     break;
    // }
    // /* Compare the differrnce between baud rate bps and clcilated
    //  * band rate. Band Rate = Ref Freq / (16 * (UBMR+1)/(UBIR+1)).
    //  * baud_diff = (src_clock_hz / divider)/(16 * (numerator / divider)/denominator). 
    //  */  
    // temp_numerator = src_clock_hz;
    // temp_denominator = (numerator << 4);
    // divider = 1;
    // /* get the approximately maximum divisor */
    // while (temp_denominator != 0)
    // {
    //     divisor = temp_denominator;
    //     temp_denominator = temp_denominator % temp_denominator;
    //     temp_numerator = divisor;
    // }
    // temp_numerator = src_clock_hz / divisor;
    // temp_denominator = (numerator << 4) / divisor;
    // baud_diff = (temp_numerator * denominator) / temp_denominator;
    // baud_diff = (baud_diff >= baud_rate) ? (baud_diff - baud_rate) : (baud_rate - baud_diff);

    // if (baud_diff < (baud_rate / 100) * 3)
    // {
    //     base->UFCR &= !UART_UFCR_DCEDTE_MASK;
    //     base->UFCR |= UART_UFCR_RFDIV(ref_freq_div);
    //     base->UBIR = UART_UBIR_INC(denominator - 1);
    //     base->UBMR = UART_UBMR_MOD(numerator / divider - 1);
    // }
}

/**
 * @描述        ： 打开指定UART
 * @参数 - base ： 要打开的串口
 * @返回值      ： 无 
 */
void uart_ensable(UART_Type *base)
{
    base->UCR1 |= (0x1 << 0);
}

/**
 * @描述        ： 关闭指定UART
 * @参数 - base ： 要关闭的串口
 * @返回值      ： 无 
 */
void uart_disable(UART_Type *base)
{
    base->UCR1 &= ~(0x1 << 0);
}

/**
 * @描述        ： 复位指定的UART
 * @参数 - base ： 要复位的串口
 * @返回值      ： 无 
 */
void uart_soft_reset(UART_Type *base)
{
    base->UCR2 &= ~(0x1 << 0);/* 复位UART */
    while ((base->UCR2 & 0x1) == 0);/* 等待复位完成 */
}

/**
 * @描述        ： 串口发送一个字符
 * @参数 - c    ： 要发送的字符
 * @返回值      ： 无 
 */
void putc_uart(UART_Type *base, uint8_t c)
{
    while (((base->UCR2 >> 3) & 0x01) == 0); /* 等待上一个数据发送完成 */
    base->UTXD = c & 0xFF;
}

/**
 * @描述        ： 串口发送一个字符串
 * @参数 - base ： 要发送的字符串
 * @返回值      ： 无 
 */
void puts_uart(UART_Type *base, char *str)
{
    char *p = str;
    while(*p) {
        putc_uart(base, *p++);
    }
}

/**
 * @描述    ：串口接收一个字符串
 * @参数    ：无
 * @返回值  ：返回接收的字符
 */
uint8_t getc_uart(UART_Type *base)
{
    while((base->USR2 & 0x1) == 0); /* 等待接收完成 */
    return base->URXD;
}

/**
 * @描述    ： 防止编译报错
 * @参数    ：无
 * @返回值  ：无
 */
void raise(int sig_nr)
{

}
